﻿using DGZImp.MdsProject.Devices.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Nomad.Iot;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DGZImp.MdsProject.Devices.Base
{
    public class TcpServe : IIotServe
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Ip { get; set; }
        public int Port { get; set; }

        /// <summary>
        /// 是否自动读取数据
        /// </summary>
        public bool IsAutoRead { get; set; } = true;

        private TcpClient Client = new TcpClient();

        public event PlcDataReceiveHandler OnPlcDataReceive;
        public event HttpDataReceiveHandler OnHttpDataReceive;
        public event TcpDataReceiveHandler OnTcpDataReceive;
        public event WebSocketDataReceiveHandler OnWebSocketDataReceive;

        private int ReceiveBufferSize { get; set; } = 1024;
        private readonly CancellationTokenSource _cts = new CancellationTokenSource();
        private NetworkStream _networkStream = null;

        public TcpServe(string id, string name, string ip, int port, bool isAutoRead = true)
        {
            Id = id;
            Name = name;
            Ip = ip;
            Port = port;
            IsAutoRead = isAutoRead;
            StartReadingAsync().ConfigureAwait(false);
        }

        public async Task StartReadingAsync()
        {
            if (!IsAutoRead) return;
            await ConnectAsync();
            await ReceiveAsync(_cts.Token);
        }

        private async Task ConnectAsync()
        {
            try
            {
                if (Client == null) Client = new TcpClient();
                await Client.ConnectAsync(Ip, Port);
                _networkStream = Client.GetStream();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error connecting to server: {ex.Message}");
            }
        }

        private async Task ReconnectAsync(CancellationToken cancellationToken)
        {
            await Task.Delay(5000);
            Console.WriteLine("Attempting to reconnect...");
            Client?.Close();
            Client?.Dispose();
            Client = null;
            _networkStream = null;

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    await ConnectAsync();
                    break;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Reconnection failed: {ex.Message}");
                    await Task.Delay(5000, cancellationToken);
                }
            }
        }

        private async Task ReceiveAsync(CancellationToken cancellationToken)
        {
            try
            {
                byte[] readBuffer = new byte[1024];
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        if (_networkStream == null) throw new SocketException(99);
                        int bytesRead = await _networkStream?.ReadAsync(readBuffer, 0, readBuffer.Length, cancellationToken);
                        if (bytesRead > 0)
                        {
                            if (OnTcpDataReceive != null)
                            {
                                OnTcpDataReceive(this, readBuffer.Take(bytesRead).ToArray());
                            }
                        }
                        else
                        {
                            //尝试发送数据检测连接
                            await _networkStream.WriteAsync(new byte[] { 0x01 });
                        }
                    }
                    catch (Exception)
                    {
                        await ReconnectAsync(cancellationToken);
                    }
                }
            }
            finally
            {
                _networkStream?.Dispose();
                Client.Close();
            }
        }

        public async Task<OperateResult> WriteAsync(byte[] bytes)
        {
            OperateResult result = new OperateResult { IsSuccess = false };
            try
            {
                if (_networkStream == null) throw new Exception("TCP Connection closed");
                await _networkStream?.WriteAsync(bytes, 0, bytes.Length);
                result.IsSuccess = true;
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        public void Dispose()
        {
            _cts?.Dispose();
        }
    }
}